package com.dems.service.util;

import com.dems.domain.ftp.FtpConfigData;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.SocketException;
import java.util.regex.Pattern;

/***
 * @author liuyq
 */
@Getter
@Setter
public class FtpUtil {
    /**
     * 定义日志文档处理
     */
    static final Logger LOGGER = LoggerFactory.getLogger(FtpUtil.class);

    private FtpConfigData ftpConfig = null;

    /**
     * 初始化ftp连接客户端
     */
    private FTPClient fclient = new FTPClient();

    public FtpUtil(FtpConfigData ftpConfig) {
        this.ftpConfig = ftpConfig;
    }


    /**
     * ftp登录方法 初始化ftp连接并验证连接是否成功
     *
     * @return boolean 返回登陆状态
     */
    private boolean login() {
        try {
            if (ftpConfig.getEndpoint() == null) {
                return false;
            }
            String[] endpoints = ftpConfig.getEndpoint().split(":");
            fclient.connect(endpoints[0], Integer.parseInt(endpoints[1]));
            fclient.enterLocalPassiveMode();
            fclient.setControlEncoding("UTF-8");
            // 初始化配置所属操作系统
            FTPClientConfig conf = new FTPClientConfig(ftpConfig.getSystem());
            conf.setServerLanguageCode("zh");
            // 登录ftp服务
            fclient.login(ftpConfig.getUserName(), ftpConfig.getPassword());
            fclient.setFileType(FTPClient.BINARY_FILE_TYPE);
            int reply = fclient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                fclient.disconnect();
                return false;
            }

        } catch (SocketException e) {
            LOGGER.error("ftp连接异常>>:{}", e.getMessage());
            return false;
        } catch (IOException e) {
            LOGGER.error("ftp连接异常>>:{}", e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 上传文件操作
     *
     * @param ftpFilePath ftp文件的存储路径
     * @param input       文件输入流
     * @return boolean返回文件上传状态
     **/
    public boolean uploadFile(String ftpFilePath, InputStream input) {
        boolean status = login();
        ftpFilePath = ftpFilePath.replace("\\\\", "/");
        if (!status) {
            LOGGER.info("文件登录失败，请检查配置信息!");
            return false;
        } else {
            try {
                fclient.setBufferSize(1024);
                int lastIndex = ftpFilePath.lastIndexOf("/");
                String fileDir = ftpFilePath.substring(0, lastIndex);
                this.checkFtpPathExist(fileDir);
                status = fclient.storeFile(ftpFilePath.substring(lastIndex + 1), input);
            } catch (IOException e) {
                LOGGER.error("文件上传异常>>:{}", e.getMessage());
                status = false;
            } finally {
                try {
                    if (input != null) {
                        input.close();
                    }
                    fclient.disconnect();
                } catch (IOException e) {
                    LOGGER.error("ftp客户端关闭异常>>:{}", e.getMessage());
                    status = false;
                }
            }
        }
        return status;
    }

    /***
     * 上传本地指定路径下磁盘文件
     *
     * @param ftpFilePath
     *            ftp文件的存储路径
     * @param srcPath
     *            待上传的本地文件路径
     * @return boolean 返回文件状态
     */
    public boolean uploadFile(String ftpFilePath, String srcPath) {
        FileInputStream finput = null;
        boolean status = true;
        try {
            finput = new FileInputStream(new File(srcPath));
            status = this.uploadFile(ftpFilePath, finput);
        } catch (FileNotFoundException e) {
            LOGGER.error("文件上传异常>>:{}", e.getMessage());
            status = false;
        } finally {
			if(finput != null){
                try {
                    finput.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
		}
        return status;
    }

    /**
     * 下载ftp文件并返回输入文件流
     *
     * @param ftpFilePath ftp文件存储路径
     * @return InputStream 返回下载文件的文件流
     */
    public InputStream downLoadFile(String ftpFilePath) {
        boolean status = this.login();
        InputStream input = null;
        if (status) {
            LOGGER.info("ftp登录成功====>>>");
            try {
                int lastIndex = ftpFilePath.lastIndexOf("/");
                String fileDir = ftpFilePath.substring(0, lastIndex);
                this.checkFtpPathExist(fileDir);
                String fileName = ftpFilePath.substring(ftpFilePath.lastIndexOf("/")+1);
                input = fclient.retrieveFileStream(fileName);
            } catch (IOException e) {
                LOGGER.error("文件下载异常>>:{}", e.getMessage());
            } finally {
                try {
                    fclient.disconnect();
                } catch (IOException e) {
                    LOGGER.error("文件下载异常>>:{}", e.getMessage());
                }
            }
        }
        return input;
    }

    /**
     * 下载ftp文件并将文件存储至本地路径中
     *
     * @param ftpFilePath ftp文件存储路径
     * @param srcPath     下载文件的本地存储路径
     * @return boolean 返回状态
     */
    public boolean downLoadFile(String ftpFilePath, String srcPath) {
        LOGGER.info("本地文件加载路径:" + srcPath);
        File file = new File(srcPath.substring(0, srcPath.lastIndexOf("/")));
        FileOutputStream fout = null;
        LOGGER.info("ftp下载路径:{}", ftpFilePath);
        boolean status = this.login();
        if (!file.exists()) {
            LOGGER.info("本地下载文件存储路径不存在>>:" + srcPath);
            file.mkdirs();
        } else {
            LOGGER.info("文件路径已存在======");
        }
        try {
            fout = new FileOutputStream(srcPath);
            try {
                int lastIndex = ftpFilePath.lastIndexOf("/");
                String fileDir = ftpFilePath.substring(0, lastIndex);
                this.checkFtpPathExist(fileDir);
                String fileName = ftpFilePath.substring(ftpFilePath.lastIndexOf("/")+1);
                status = fclient.retrieveFile(fileName, fout);
                fout.flush();
                if (fout != null) {
                    fout.close();
                }
            } catch (IOException e) {
                LOGGER.error("文件下载异常:" + e.getMessage());
                status = false;
            }
        } catch (FileNotFoundException e) {
            LOGGER.error("文件不存在:" + e.getMessage());
            status = false;
        } finally {
            try {
				if(fout != null){
					fout.close();
				}
                fclient.disconnect();
            } catch (IOException e) {
                LOGGER.error("ftp客户端关闭异常");
                status = false;
            }
        }
        return status;
    }

    /**
     * 判断ftp文件目录是否存在，不存在则创建
     *
     * @param ftpPath ftp路径
     */
    public void checkFtpPathExist(String ftpPath) {
        String[] paths = ftpPath.split("/");
        for (String dir : paths) {
            try {
                if (!fclient.changeWorkingDirectory(dir)) {
                    fclient.makeDirectory(dir);
                    fclient.changeWorkingDirectory(dir);
                }
            } catch (IOException e) {
                LOGGER.error("文件路径切换异常!");
            }
        }
    }

    /**
     * 文件路径的合法性校验
     *
     * @param path
     */
    public boolean checkFilePath(String path) {
        String pattern = "\"^[A-z]:\\\\\\\\(.+?\\\\\\\\)*$\"";
        return Pattern.matches(pattern, path);
    }

    /**
     * 返回本地路径
     */
    public String getLocalPath() {
        return this.ftpConfig.getLocalPath();
    }
}
